#include "TextureQuad.h"
#include "TexPt.h"

#include <cstdio>
#include "opencv/cv.h"

using namespace std;

TextureQuad::TextureQuad() {
	startTexID = endTexID = 0xdeadbeef;
	frame = 0;
}

TextureQuad::TextureQuad(GLuint startTexID, GLuint endTexID,
		GLuint *fadeTexIDs, int dynamicFrames, int staticFrames) {
	this->startTexID = startTexID;
	this->endTexID = endTexID;
	this->dynamicFrames = dynamicFrames;
	this->fadeTexIDs = fadeTexIDs;
	this->staticFrames = staticFrames;
	frame = 0;
	this->bounds[0] = dynamicFrames;
	this->bounds[1] = dynamicFrames + staticFrames;
	this->bounds[2] = bounds[0] + bounds[1];
}

void TextureQuad::getGLProjTransMat(CvPoint2D32f dstQuadPts[4],
		CvPoint2D32f srcQuadPts[4], GLfloat glProjTransMat[16]) {
	CvMat * cvProjTransMat = cvCreateMat(3, 3, CV_32FC1);
	float *flProjTransMat;

	for (int i = 0; i < 16; i++) {
		if (i % 5 != 0)
			glProjTransMat[i] = 0.0;
		else
			glProjTransMat[i] = 1.0;
	}

	cvGetPerspectiveTransform(srcQuadPts, dstQuadPts, cvProjTransMat);

	flProjTransMat = cvProjTransMat->data.fl;

	glProjTransMat[0] = flProjTransMat[0];
	glProjTransMat[4] = flProjTransMat[1];
	glProjTransMat[12] = flProjTransMat[2];

	glProjTransMat[1] = flProjTransMat[3];
	glProjTransMat[5] = flProjTransMat[4];
	glProjTransMat[13] = flProjTransMat[5];

	glProjTransMat[3] = flProjTransMat[6];
	glProjTransMat[7] = flProjTransMat[7];
	glProjTransMat[15] = flProjTransMat[8];
}

void TextureQuad::draw() {
	if (!start[0].isValid() || !end[0].isValid())
		return;

	TexPt* current = 0;
	TexPt tmp[8];
	int texID = 0, tmpFrame;
	GLfloat glProjTransMat[16];
	CvPoint2D32f dstQuadPts[4];
	CvPoint2D32f srcQuadPts[4];

	if (frame >= bounds[2]) {
		frame = 0;
	}

	if (frame < bounds[0]) {
		current = start;
		texID = startTexID;
		tmpFrame = frame;

	} else if (frame >= bounds[1]) {
		current = end;
		texID = endTexID;
		tmpFrame = frame - bounds[1];

	} else {
		for (int i = 0; i < 4; i++) {
			tmp[i].x = start[i].x + (dynamicFrames + 1) * start[i + 4].x;
			tmp[i].y = start[i].y + (dynamicFrames + 1) * start[i + 4].y;

			tmp[i + 4].x = (end[i].x - tmp[i].x) / (float) (staticFrames - 1);
			tmp[i + 4].y = (end[i].y - tmp[i].y) / (float) (staticFrames - 1);
		}

		current = tmp;
		tmpFrame = frame - dynamicFrames;
		texID = fadeTexIDs[tmpFrame];
	}

	srcQuadPts[0].x = 0;
	srcQuadPts[0].y = 0;
	srcQuadPts[1].x = 1.;
	srcQuadPts[1].y = 0;
	srcQuadPts[2].x = 1.;
	srcQuadPts[2].y = 1.;
	srcQuadPts[3].x = 0;
	srcQuadPts[3].y = 1.;

	for (int i = 0; i < 4; i++) {
		dstQuadPts[i] = cvPoint2D32f(
				current[i].x + tmpFrame * current[i + 4].x, current[i].y
						+ tmpFrame * current[i + 4].y);
	}

	getGLProjTransMat(dstQuadPts, srcQuadPts, glProjTransMat);

	//	for (int i = 0; i < 16; i++) {
	//		if (i % 4 == 0)
	//			printf("\n");
	//		printf("%f\t", glProjTransMat[i]);
	//	}
	//	printf("\n");

	glMatrixMode(GL_TEXTURE);
	glLoadIdentity();
	glMultMatrixf(glProjTransMat);

	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, texID);
	glBegin(GL_QUADS);
	{
		double x = current[0].x + tmpFrame * current[4].x;
		double y = current[0].y + tmpFrame * current[4].y;
		glTexCoord2d(x, y);
		glVertex2d(-1, -1);

		x = current[1].x + tmpFrame * current[5].x;
		y = current[1].y + tmpFrame * current[5].y;

		glTexCoord2d(x, y);
		glVertex2d(1, -1);

		x = current[2].x + tmpFrame * current[6].x;
		y = current[2].y + tmpFrame * current[6].y;
		glTexCoord2d(x, y);
		glVertex2d(1, 1);

		x = current[3].x + tmpFrame * current[7].x;
		y = current[3].y + tmpFrame * current[7].y;
		glTexCoord2d(x, y);
		glVertex2d(-1, 1);
	}
	glEnd();
	glDisable(GL_TEXTURE_2D);
}

void TextureQuad::incrFrame() {
	frame++;
}

void TextureQuad::update(OpenGLImage* image) {
	if (image->getTexID() == startTexID) {
		if (!image->convWinPtToTexPt(start, &start[4]))
			return;
		for (int i = 0; i < 4; i++) {
			start[i + 4].x = (start[i + 4].x - start[i].x)
					/ (float) (dynamicFrames - 1);
			start[i + 4].y = (start[i + 4].y - start[i].y)
					/ (float) (dynamicFrames - 1);
		}
	} else if (image->getTexID() == endTexID) {
		if (!image->convWinPtToTexPt(end, &end[4]))
			return;
		for (int i = 0; i < 4; i++) {
			end[i + 4].x = (end[i + 4].x - end[i].x) / (float) (dynamicFrames
					- 1);
			end[i + 4].y = (end[i + 4].y - end[i].y) / (float) (dynamicFrames
					- 1);
		}
	}
}
